package com.example.Holo.uiactivities;

import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.SectionIndexer;
import android.widget.TextView;
import com.actionbarsherlock.app.SherlockActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.example.Holo.R;
import com.example.Holo.parameters.IntentConstants;
import com.example.Holo.uiactivities.components.indexablelist.IndexableListView;
import com.example.Holo.uiactivities.components.indexablelist.StringMatcher;
import com.example.Holo.utils.functions.IIn;
import com.google.common.base.Supplier;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static android.content.Intent.ACTION_VIEW;
import static android.graphics.Color.BLACK;
import static android.graphics.Color.rgb;
import static android.graphics.Typeface.BOLD;
import static android.graphics.Typeface.NORMAL;
import static android.net.Uri.withAppendedPath;
import static android.provider.BaseColumns._ID;
import static android.provider.ContactsContract.Contacts.CONTENT_URI;
import static android.provider.ContactsContract.Contacts.DISPLAY_NAME;
import static android.provider.ContactsContract.Contacts.HAS_PHONE_NUMBER;
import static android.provider.ContactsContract.Contacts.STARRED;
import static com.example.Holo.parameters.IntentConstants.NAMES;
import static com.example.Holo.utils.collections.Sequences.each;
import static com.google.common.base.Suppliers.memoize;
import static java.lang.Character.toLowerCase;
import static java.lang.String.valueOf;
import static java.util.Collections.sort;

public class PickFriendsActivity extends SherlockActivity {

    private List<Contact> contacts = new ArrayList<Contact>();
    private ContentAdapter adapter;

    private final static String[] PROJECTION = new String[]{_ID, DISPLAY_NAME, STARRED};
    private final static String SELECTION = HAS_PHONE_NUMBER + " = '1'";

    private final Set<Integer> selection = new HashSet<Integer>();

    private String mSections = "#ABCDEFGHIJKLMNOPQRSTUVWXYZАБВГДЕЄЖЗИІЙКЛМНОПРСТУФХЦЧШЩЮЯ";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setTitle(R.string.pick_friends);
        setContentView(R.layout.pick_friends_activity);

        adapter = new ContentAdapter(this, android.R.layout.simple_list_item_1, contacts);

        final IndexableListView listView = (IndexableListView) findViewById(R.id.listview);
        listView.setAdapter(adapter);
        listView.setFastScrollEnabled(true);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                final Contact contact = contacts.get(position);
                if ( !contact.isHeader ) {
                    final boolean isPreviouslySelected = selection.contains(position);
                    if ( isPreviouslySelected ) {
                        selection.remove(position);
                    } else {
                        selection.add(position);
                    }
                    setSelected(!isPreviouslySelected, view);
                }
            }
        });

        loader.loadAndShow(SELECTION);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getSupportMenuInflater().inflate(R.menu.pick_friends_menu, menu);
        return true;
    }

    @SuppressWarnings("UnusedDeclaration")
    public void addFriendsHandler(MenuItem item) {
        final Intent intent = new Intent();
        intent.putStringArrayListExtra(NAMES, (ArrayList<String>)getSelectedNames());
        setResult(RESULT_OK, intent);
        finish();
    }

    private List<String> getSelectedNames() {
        final List<String> result = new ArrayList<String>();
        for ( Integer index : selection ) {
            result.add(contacts.get(index).name);
        }
        return result;
    }

    interface ILoader {
        void loadAndShow(String condition);
    }

    private final ILoader loader = new ILoader() {
        @Override
        public void loadAndShow(final String condition) {
            final Map<String, String> result = memoize(new Supplier<Map<String, String>>() {
                @Override
                public Map<String, String> get() {
                    return getContacts(condition);
                }
            }).get();
            contacts.clear();
            final List<String> collection = new ArrayList<String>(result.keySet());
            sort(collection, comparator);
            each(collection, addElementFunctor);
            if (adapter != null) {
                initHeaders(contacts);
                adapter.notifyDataSetChanged();
            }
        }
    };

    private void initHeaders(List<Contact> contacts) {
        for (int i = 0; i < mSections.length(); i++) {
            final char character = mSections.charAt(i);
            for (Contact item : contacts) {
                if (toLowerCase(item.name.charAt(0)) == toLowerCase(character)) {
                    final int index = contacts.indexOf(item);
                    contacts.add(index, new Contact(Character.toString(character), true));
                    break;
                }
            }
        }
    }

    private Map<String, String> getContacts(String condition) {
        final Map<String, String> contactMap = new HashMap<String, String>();
        final ContentResolver cr = getContentResolver();
        final Cursor cursor = cr.query(CONTENT_URI, PROJECTION, condition, null, null);
        while (cursor.moveToNext()) {
            final String contactID = cursor.getString(cursor.getColumnIndex(_ID));
            final Intent intent = new Intent(ACTION_VIEW);
            final Uri uri = withAppendedPath(CONTENT_URI, valueOf(contactID));
            intent.setData(uri);
            final String title = (cursor.getString(cursor.getColumnIndex(DISPLAY_NAME)));
            contactMap.put(title, intent.toUri(0));
        }
        cursor.close();
        return contactMap;
    }

    private static final Comparator<String> comparator = new Comparator<String>() {
        @Override
        public int compare(String first, String second) {
            return first.compareTo(second);
        }
    };

    private class ContentAdapter extends ArrayAdapter<Contact> implements SectionIndexer {

        public ContentAdapter(Context context, int textViewResourceId,
                              List<Contact> objects) {
            super(context, textViewResourceId, objects);
        }

        @Override
        public int getPositionForSection(int section) {
            // If there is no item for current section, previous section will be selected
            for (int i = section; i >= 0; i--) {
                for (int j = 0; j < getCount(); j++) {
                    if (i == 0) {
                        // For numeric section
                        for (int k = 0; k <= 9; k++) {
                            if (StringMatcher.match(String.valueOf(getItem(j).name.charAt(0)), String.valueOf(k)))
                                return j;
                        }
                    } else {
                        if (StringMatcher.match(String.valueOf(getItem(j).name.charAt(0)), String.valueOf(mSections.charAt(i))))
                            return j;
                    }
                }
            }
            return 0;
        }

        @Override
        public int getSectionForPosition(int position) {
            return 0;
        }

        @Override
        public Object[] getSections() {
            String[] sections = new String[mSections.length()];
            for (int i = 0; i < mSections.length(); i++)
                sections[i] = String.valueOf(mSections.charAt(i));
            return sections;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            final Contact contact = contacts.get(position);
            final TextView view = (TextView) super.getView(position, convertView, parent);
            view.setTextColor(Color.WHITE);
            if (contact.isHeader) {
                view.setBackgroundColor(rgb(220, 127, 127));
                view.setTypeface(null, BOLD);
            } else {
                view.setBackgroundColor(Color.BLACK);
                view.setTypeface(null, NORMAL);
            }
            view.setTextSize(16);
            view.setMaxLines(2);
            view.setText(contact.name);
            return view;
        }
    }

    private static void setSelected(boolean isSelected, View view) {
        view.setBackgroundColor(isSelected ? Color.argb(255, 154, 210, 96) : BLACK);
    }

    class Contact {

        public final String name;
        public final boolean isHeader;

        Contact(String name, boolean isHeader) {
            this.name = name;
            this.isHeader = isHeader;
        }
    }

    private final IIn<String> addElementFunctor = new IIn<String>() {
        @Override
        public void in(String name) {
            contacts.add(new Contact(name, false));
        }
    };
}
